package com.codebo.homiematchbackend.controller;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.codebo.homiematchbackend.annotation.AuthCheck;
import com.codebo.homiematchbackend.common.BaseResponse;
import com.codebo.homiematchbackend.common.DeleteRequest;
import com.codebo.homiematchbackend.common.ErrorCode;
import com.codebo.homiematchbackend.common.ResultUtils;
import com.codebo.homiematchbackend.constant.UserConstant;
import com.codebo.homiematchbackend.exception.BusinessException;
import com.codebo.homiematchbackend.exception.ThrowUtils;
import com.codebo.homiematchbackend.model.dto.team.JoinTeamRequest;
import com.codebo.homiematchbackend.model.dto.team.TeamAddRequest;
import com.codebo.homiematchbackend.model.dto.team.TeamQueryRequest;
import com.codebo.homiematchbackend.model.entity.Team;
import com.codebo.homiematchbackend.model.entity.User;
import com.codebo.homiematchbackend.model.vo.TeamVO;
import com.codebo.homiematchbackend.service.TeamService;
import com.codebo.homiematchbackend.service.UserService;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.http.MediaType;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.time.Duration;
import java.util.List;
import java.util.concurrent.TimeUnit;

@RequestMapping("/team")
@RestController
public class TeamController
{
    @Resource
    private TeamService teamService;

    @Resource
    private UserService userService;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    private final Cache<String, String> LOCAL_CACHE = Caffeine.newBuilder()
            .initialCapacity(1024)
            .maximumSize(10_000L) // 最大 10000 条
            // 缓存 5 分钟后移除
            .expireAfterWrite(Duration.ofMinutes(5))
            .build();


    //    @ParameterObject
    @PostMapping(value = "/add", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    public BaseResponse<Long> addTeam(@RequestPart(value = "file", required = false) MultipartFile multipartFile,
                                      @RequestPart("data") TeamAddRequest teamAddRequest,
                                      HttpServletRequest httpServletRequest)
    {
        System.out.println("multipartFile = " + multipartFile);
        ThrowUtils.throwIf(teamAddRequest == null, ErrorCode.PARAMS_ERROR);
        User loginUser = userService.getLoginUser(httpServletRequest);
        ThrowUtils.throwIf(loginUser == null, ErrorCode.NOT_LOGIN_ERROR);
        System.out.println("teamAddRequest = " + teamAddRequest);
        long id = teamService.addTeam(multipartFile, teamAddRequest, loginUser);
        return ResultUtils.success(id);
    }

    @GetMapping("/{id}")
    public BaseResponse<TeamVO> getTeamById(@PathVariable("id") Long id, HttpServletRequest httpServletRequest)
    {
        Team team = teamService.getById(id);
        return ResultUtils.success(teamService.getTeamVO(team));
    }

    @PostMapping("/delete")
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    public BaseResponse<Boolean> deleteTeam(@RequestBody DeleteRequest deleteRequest)
    {
        if (deleteRequest == null || deleteRequest.getId() <= 0)
        {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        boolean b = teamService.removeById(deleteRequest.getId());
        return ResultUtils.success(b);
    }

    @PostMapping("/join")
    @AuthCheck(mustRole = UserConstant.DEFAULT_ROLE)
    public BaseResponse<Boolean> joinTeam(@RequestBody JoinTeamRequest joinTeamRequest)
    {
        ThrowUtils.throwIf(joinTeamRequest == null, ErrorCode.PARAMS_ERROR);
        boolean result = teamService.joinTeam(joinTeamRequest);
        return ResultUtils.success(result);
    }

    @PostMapping("/list/page/vo")
    public BaseResponse<Page<TeamVO>> listTeamVoByPage(@RequestBody TeamQueryRequest teamQueryRequest)
    {
        ThrowUtils.throwIf(teamQueryRequest == null, ErrorCode.PARAMS_ERROR);
        int current = teamQueryRequest.getCurrent();
        int pageSize = teamQueryRequest.getPageSize();
        Page<Team> teamPage = teamService.page(new Page<>(current, pageSize), teamService.getQueryWrapper(teamQueryRequest));
        Page<TeamVO> teamVOPage = new Page<>(current, pageSize, teamPage.getTotal());
        teamVOPage.setRecords(teamService.getTeamVOList(teamPage.getRecords()));
        return ResultUtils.success(teamVOPage);

    }

    @PostMapping("/list/recommend")
    @AuthCheck(mustRole = UserConstant.DEFAULT_ROLE)
    public BaseResponse<Page<TeamVO>> listTeamByRecommend(@RequestBody TeamQueryRequest teamQueryRequest, HttpServletRequest httpServletRequest)
    {
        ThrowUtils.throwIf(teamQueryRequest == null, ErrorCode.PARAMS_ERROR);
        Boolean isRefresh = teamQueryRequest.getIsRefresh();
        //使得缓存是同一份，不然构建的key不一样
        teamQueryRequest.setIsRefresh(false);
        ThrowUtils.throwIf(isRefresh == null, ErrorCode.PARAMS_ERROR);
        //构建缓存key
        String queryCondition = JSONUtil.toJsonStr(teamQueryRequest) + JSONUtil.toJsonStr(userService.getLoginUser(httpServletRequest));
        String hashKey = DigestUtils.md5DigestAsHex(queryCondition.getBytes());
        String cacheKey = String.format("HomieMatch:listTeamByRecommend:%s", hashKey);

        int current = teamQueryRequest.getCurrent();
        int pageSize = teamQueryRequest.getPageSize();
        ValueOperations<String, String> opsForValue = stringRedisTemplate.opsForValue();

        //判断是否为刷新
        if (!isRefresh)
        {
            //不是刷新，走缓存
            // 1. 先从本地缓存中查询
            String cachedValue = LOCAL_CACHE.getIfPresent(cacheKey);
            if (cachedValue != null)
            {
                // 如果缓存命中，返回结果
                List<TeamVO> cachedList = JSONUtil.toList(new JSONArray(cachedValue), TeamVO.class);
                Page<TeamVO> cachedPage = new Page<>(current, pageSize, cachedList.size());
                cachedPage.setRecords(cachedList);
                return ResultUtils.success(cachedPage);
            }
            // 2. 本地缓存未命中，查询 Redis 分布式缓存

            cachedValue = opsForValue.get(cacheKey);
            if (cachedValue != null)
            {
                // 如果缓存命中，更新本地缓存，返回结果
                LOCAL_CACHE.put(cacheKey, cachedValue);
                List<TeamVO> cachedList = JSONUtil.toList(new JSONArray(cachedValue), TeamVO.class);
                Page<TeamVO> cachedPage = new Page<>(current, pageSize, cachedList.size());
                cachedPage.setRecords(cachedList);
                return ResultUtils.success(cachedPage);
            }
        }
        // 3. 查询数据库
        //根据条件查询用户
//        Page<User> userPage = userService.page(new Page<>(current, pageSize), userService.getQueryWrapper(userQueryRequest));
        //按相似度进行排序
        List<TeamVO> teamVOList = teamService.listTeamByRecommend(httpServletRequest, teamQueryRequest);
        if (teamVOList.isEmpty())
        {
            return ResultUtils.success(new Page<>(current, pageSize));
        }

        // 4. 更新缓存
        // 更新 Redis 缓存
        String cacheValue = JSONUtil.toJsonStr(teamVOList);
        // 设置缓存的过期时间，5 - 10 分钟过期，防止缓存雪崩
        int cacheExpireTime = 300 + RandomUtil.randomInt(0, 300);
        opsForValue.set(cacheKey, cacheValue, cacheExpireTime, TimeUnit.SECONDS);
        // 写入本地缓存
        LOCAL_CACHE.put(cacheKey, cacheValue);

        Page<TeamVO> teamVOPage = new Page<>(current, pageSize, teamVOList.size());
        teamVOPage.setRecords(teamVOList);
        return ResultUtils.success(teamVOPage);
    }


}
